﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using MLRobotic.Tower.Messaging;
using MLRobotic.Tower.Common;

namespace MLRobotic.Tower.Forms
{
    public partial class SerialPortsControl : UserControl
    {
        private ControlTower _controlTower;
        private Config _config;

        public SerialPortsControl(ControlTower controlTower, Config config)
        {
            _controlTower = controlTower;
            _config = config;

            InitializeComponent();
            Init();
        }

        private enum PortState
        {
            Closed,
            Opened,
            Tested,
            InError
        }

        private void Init()
        {
            Messenger.Instance.WhoIsResponse = (com, type) => this.com_DataReceived(com, type);

            var ports = SerialPort.GetPortNames().OrderBy(p => p);

            foreach (var port in ports)
                cb1.Items.Add(port);

            foreach (var port in ports)
                cb2.Items.Add(port);

            foreach (var port in ports)
                cb3.Items.Add(port);

            if (_config.IsTouchPro2())
            {
                if (cb1.Items.Contains("COM2"))
                    cb1.SelectedItem = "COM2";

                //if (cb2.Items.Contains("COM2"))
                //    cb2.SelectedItem = "COM2";

                if (cb3.Items.Contains("COM1"))
                    cb3.SelectedItem = "COM1";
            }
            else
            {
                if (cb3.Items.Contains("COM7"))
                    cb3.SelectedItem = "COM7";
            }
        }

        private PortState Open(ref COM com, string name)
        {
            if (String.IsNullOrEmpty(name))
                return PortState.InError;

            Close(ref com);

            try
            {
                com = new COM(name);
                return PortState.Opened;
            }
            catch (Exception ex)
            {
                txtError.Text += ex.Message + Environment.NewLine; 
            }

            Close(ref com);
            return PortState.InError;
        }

        private PortState Close(ref COM com)
        {
            if (com != null)
            {
                try
                {
                    com.Dispose();
                }
                catch (Exception ex)
                {
                    txtError.Text += ex.Message + Environment.NewLine;
                    return PortState.InError;
                }
                finally
                {
                    com = null;
                }
            }

            return PortState.Closed;
        }

        private PortState Test(ref COM com)
        {
            if (com != null && com.IsOpen)
            {
                try
                {
                    com.Send(PacketType.WhoIs);
                    return PortState.Opened;
                }
                catch (Exception ex)
                {
                    txtError.Text += ex.Message + Environment.NewLine;
                    Close(ref com);
                    return PortState.InError;
                }
            }

            return PortState.Closed;
        }

        private Color GetStateColor(PortState state)
        {
            switch (state)
            {
                case PortState.InError:
                    return Color.Red;
                case PortState.Opened:
                    return Color.Orange;
                case PortState.Tested:
                    return Color.Green;
                default:
                    return Color.DarkGray;
            }
        }

        private void btnOpen1_Click(object sender, EventArgs e)
        {
            panelState1.BackColor = GetStateColor(Open(ref _controlTower.ComRobot1, (string)cb1.SelectedItem));
        }

        private void btnOpen2_Click(object sender, EventArgs e)
        {
            panelState2.BackColor = GetStateColor(Open(ref _controlTower.ComRobot2, (string)cb2.SelectedItem));
        }
        
        private void btnOpen3_Click(object sender, EventArgs e)
        {
            panelState3.BackColor = GetStateColor(Open(ref _controlTower.ComPhone, (string)cb3.SelectedItem));
        }
        
        private void btnTest1_Click(object sender, EventArgs e)
        {
            panelState1.BackColor = GetStateColor(Test(ref _controlTower.ComRobot1));
        }

        private void btnTest2_Click(object sender, EventArgs e)
        {
            panelState2.BackColor = GetStateColor(Test(ref _controlTower.ComRobot2));
        }

        private void btnTest3_Click(object sender, EventArgs e)
        {
            panelState3.BackColor = GetStateColor(Test(ref _controlTower.ComPhone));
        }
        
        private void btnClose1_Click(object sender, EventArgs e)
        {
            panelState1.BackColor = GetStateColor(Close(ref _controlTower.ComRobot1));
        }
        
        private void btnClose2_Click(object sender, EventArgs e)
        {
            panelState2.BackColor = GetStateColor(Close(ref _controlTower.ComRobot2));
        }
        
        private void btnClose3_Click(object sender, EventArgs e)
        {
            panelState3.BackColor = GetStateColor(Close(ref _controlTower.ComPhone));
        }

        private void cb1_SelectedIndexChanged(object sender, EventArgs e)
        {
            panelState1.BackColor = GetStateColor(Close(ref _controlTower.ComRobot1));
        }

        private void cb2_SelectedIndexChanged(object sender, EventArgs e)
        {
            panelState2.BackColor = GetStateColor(Close(ref _controlTower.ComRobot2));
        }

        private void cb3_SelectedIndexChanged(object sender, EventArgs e)
        {
            panelState3.BackColor = GetStateColor(Close(ref _controlTower.ComPhone));
        }

        private void com_DataReceived(COM sender, PacketType packetType)
        {
            GotWhoIsResponse(sender, ref _controlTower.ComRobot1, packetType, PacketType.Robot1, panelState1);
            GotWhoIsResponse(sender, ref _controlTower.ComRobot2, packetType, PacketType.Robot2, panelState2);

            if (_config.IsTouchPro2())
                GotWhoIsResponse(sender, ref _controlTower.ComPhone, packetType, PacketType.Phone2, panelState3);
            else
                GotWhoIsResponse(sender, ref _controlTower.ComPhone, packetType, PacketType.Phone1, panelState3);
        }

        private void GotWhoIsResponse(COM sender, ref COM target, PacketType packetType, PacketType targetPacketType, Panel panel)
        {
            if (sender == target)
            {
                if (packetType == targetPacketType)
                {
                    panel.BackColor = GetStateColor(PortState.Tested);
                }
                else
                {
                    Close(ref target);
                    panel.BackColor = GetStateColor(PortState.InError);
                    txtError.Text += string.Format("Wrong receiver: should be {0} but is {1}", targetPacketType, packetType) + Environment.NewLine;
                }
            }
        }
    }
}
